package com.dualsportmaps.android;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;

import net.osmand.plus.OsmandSettings;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;

import android.content.pm.PackageInfo;
import android.provider.Settings.Secure;
import android.util.Log;

import com.dualsportmaps.android.shared.DatabaseProceduresAndroidImplRequest;
import com.dualsportmaps.android.shared.DsmRequestFactory;
import com.dualsportmaps.android.shared.model.DsmMapProxy;
import com.google.web.bindery.event.shared.SimpleEventBus;
import com.google.web.bindery.event.shared.UmbrellaException;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.RequestTransport;
import com.google.web.bindery.requestfactory.shared.ServerFailure;
import com.google.web.bindery.requestfactory.vm.RequestFactorySource;

public class DsmConnectionFactory implements RequestTransport {
	public static final String mainURL = "http://www.dualsportmaps.com";
	private static List<Cookie> cookies = null;
	
	public static String getCookies() {
		String returnedCookies = "";
		for(Cookie cookie : cookies) {
			returnedCookies += cookie.getName() +"="+cookie.getValue();
		}
		return returnedCookies;
	}
	
	public static DsmRequestFactory getDsmRequestFactory() {
		DsmRequestFactory drf = RequestFactorySource.create(DsmRequestFactory.class);
		SimpleEventBus eb = new SimpleEventBus();
		drf.initialize(eb, new DsmConnectionFactory());
		return drf;
	}
	public static DatabaseProceduresAndroidImplRequest getDsmConnection() {
		return getDsmRequestFactory().databaseProceduresRequest();
	}
	private static boolean waitingForAuthentication = false;
	public static void addDsmAppUserLocation(final double dsmAppUserLocationLat,final double dsmAppUserLocationLng) {
		final String appUserName = OsmandSettings.getDsmUserName(OsmandSettings.getPrefs(DsmResourceManager.getApplicationContext()));
		final String password = OsmandSettings.getDsmUserPassword(OsmandSettings.getPrefs(DsmResourceManager.getApplicationContext()));
		if(appUserName.length() > 0 && password.length() > 0) {
			new Thread(new Runnable(){
				@Override
				public void run() {
					try {
						authenticateDsmAppUser();
						getDsmConnection().addDsmAppUserLocation(dsmAppUserLocationLat, dsmAppUserLocationLng).fire();
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}).start();
		}
	}
	public static void addDsmAppUseHistory() {
		final String dsmAppUserHandle = OsmandSettings.getDsmUserName(OsmandSettings.getPrefs(DsmResourceManager.getApplicationContext()));
		new Thread(new Runnable(){
			@Override
			public void run() {
				try {
					String appVersion = "";
					String appDeviceId = "";
					try {
						PackageInfo info = DsmResourceManager.getApplicationContext().getPackageManager().getPackageInfo(DsmResourceManager.getApplicationContext().getPackageName(), 0);
						if (info != null) {
							appVersion = info.versionName;
						}
						appDeviceId = Secure.getString(DsmResourceManager.getApplicationContext().getContentResolver(),Secure.ANDROID_ID);
					} catch (Throwable e) {
					}
					getDsmConnection().addAppUseHistory(dsmAppUserHandle, appVersion, appDeviceId).fire();
				} catch (Throwable e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}).start();
	}
	public static void authenticateDsmAppUser() {
		try {
			final String appUserName = OsmandSettings.getDsmUserName(OsmandSettings.getPrefs(DsmResourceManager.getApplicationContext()));
			final String password = OsmandSettings.getDsmUserPassword(OsmandSettings.getPrefs(DsmResourceManager.getApplicationContext()));
			if(appUserName.length() > 0 && password.length() > 0) {
				waitingForAuthentication = true;
				try {
					Request<String> checkReq = getDsmConnection().getDsmAppUserHandle();
					checkReq.fire(new Receiver<String>(){
						@Override
						public void onSuccess(String response) {
							if(response == null)
								response = "";
							if(!response.equalsIgnoreCase(appUserName)) {
								Request<Boolean> createReq = getDsmConnection().authenticateDsmAppUser(appUserName,password);
								createReq.fire(new Receiver<Boolean>(){
									@Override
									public void onSuccess(Boolean response) {
										Log.d("DsmConnectionFactory", "authenticated " + response);
										waitingForAuthentication = false;
									}

									@Override
									public void onFailure(ServerFailure error) {
										Log.d("DsmConnectionFactory", "authentication failed");
										waitingForAuthentication = false;
									}
									
								}
								);
							} else {
								waitingForAuthentication = false;
							}
						}

						@Override
						public void onFailure(ServerFailure error) {
							waitingForAuthentication = false;
						}
					}
					);
				} catch (UmbrellaException e) {
					waitingForAuthentication = false;
					if(e.getCause().getMessage().contains("ClassCastException")) {
						//log in worked
					}
				}
				int waiting=0;
				while(waitingForAuthentication) {
					try {
						waiting++;
						if(waiting > 30)
							waitingForAuthentication = false;
						Thread.sleep(100);
					} catch (InterruptedException e) {}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void send(String payload, TransportReceiver receiver) {
		DefaultHttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost();
        post.setHeader("Content-Type", "application/json;charset=UTF-8");
        post.setHeader("User-Agent", "dsm-android-client");
        post.setHeader("Accept-Encoding", "gzip, deflate");
        if(cookies != null)
	        for(Cookie cookie:cookies) {
	        	client.getCookieStore().addCookie(cookie);
	        }

        try {
            post.setURI(new URI(mainURL+"/dsmRequest24"));
            post.setEntity(new StringEntity(payload, "UTF-8"));
            HttpResponse response = client.execute(post);
            String contents = null;
            ServerFailure serverFailure = null;
            boolean success = false;
            if (200 == response.getStatusLine().getStatusCode()) {
            	success = true;
                cookies = client.getCookieStore().getCookies();
                Header ceheader = response.getEntity().getContentEncoding();
            	InputStream in = response.getEntity().getContent();
                if (ceheader != null) {
                	HeaderElement[] codecs = ceheader.getElements();
                	for (int i = 0; i < codecs.length; i++) {
            			if (codecs[i].getName().equalsIgnoreCase("gzip")) {
            				in = new GZIPInputStream(in);
            			} else if (codecs[i].getName().equalsIgnoreCase("deflate")) {
            		        in = new InflaterInputStream(in);
            		    }
                	}
                }
            	contents = readStreamAsString(in);
            } else {
            	serverFailure = new ServerFailure(response.getStatusLine().getReasonPhrase());
            }
            client.getConnectionManager().shutdown();
            if(success)
            	receiver.onTransportSuccess(contents);
            else
            	receiver.onTransportFailure(serverFailure);
            return;
        } catch (Throwable e) {
        	receiver.onTransportFailure(new ServerFailure(e.getMessage()));
            e.printStackTrace();
        }
    }

    /**
     * Reads an entire input stream as a String. Closes the input stream.
     */
    private String readStreamAsString(InputStream in) {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
            byte[] buffer = new byte[4096];
            int count;
            do {
                count = in.read(buffer);
                if (count > 0) {
                    out.write(buffer, 0, count);
                }
            } while (count >= 0);
            return out.toString("UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("The JVM does not support the compiler's default encoding.",
                    e);
        } catch (IOException e) {
            return null;
        } finally {
            try {
                in.close();
            } catch (IOException ignored) {
            }
        }
    }
	public static void test() {
		SimpleEventBus eb = new SimpleEventBus();
		DsmRequestFactory f = RequestFactorySource.create(DsmRequestFactory.class);
		f.initialize(eb, new DsmConnectionFactory());
		try {
			Request<Boolean> createReq = getDsmConnection().authenticateDsmAppUser("test","Tets");
			createReq.fire(new Receiver<Boolean>(){
				@Override
				public void onSuccess(Boolean response) {
					System.out.println(response);
				}});
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		getDsmConnection().getDsmAppUserHandle().fire(new Receiver<String>(){
			@Override
			public void onSuccess(String response) {
				System.out.println(response);
			}});
		getDsmConnection().getDsmMap("48934873-3E7D-44A6-8E72-0ED4D7C6158C").fire(new Receiver<DsmMapProxy>(){
			@Override
			public void onSuccess(DsmMapProxy response) {
				System.out.println(response.getDsmMapName());
			}});
	}	

}
